package pluginUtils;

public class CircleInversion {

	private Circle ci;
	private Complexe center; 
	private double radius; 
	
	public CircleInversion(Circle ci) {
		this.ci = ci;
		this.center=ci.getCenter();
		this.radius=ci.getRadius(); 
	}
	
	public String toString(){
		return "Invertor "+ci;  
	}

	public Circle inverte(Circle c){
		double dist=Complexe.distance(c.getCenter(),this.center); 
		double powerO=dist*dist-c.getRadius()*c.getRadius(); 
		double alpha=this.radius*this.radius/powerO; 
		double rayon=Math.abs(alpha*c.getRadius());
		
		double x=center.getReal()+alpha*(c.getCenter().getReal()-center.getReal());
		double y=center.getIm()+alpha*(c.getCenter().getIm()-center.getIm());
		Complexe centre=Complexe.createComplexeFromRI(x,y); 
		return new Circle(centre,rayon); 
	}
	
	public AGCircle inverte(AGCircle c){
		Circle cc=this.inverte((Circle) c); 
		AGCircle agc=new AGCircle(cc.getCenter(),cc.getRadius(),c.isInverted(),c.getColor()); 
		return agc;
	}
	
	
	public DoyleCircle inverte(DoyleCircle dc){
		Circle co=this.inverte(dc.getCircle()); 
		return new DoyleCircle(co.getCenter(),dc.getRotation(),co.getRadius(),dc.getApower(),dc.getBpower()); 
		
	}
	
	public DoyleCircleWithNeighbours inverte(DoyleCircleWithNeighbours dc){
		Circle co=this.inverte(dc.getCircle()); 
		DoyleCircleWithNeighbours nouvo=DoyleCircleWithNeighbours.makeCircle(co.getCenter().getArgument(),co.getCenter().getIm(),dc.getRotation(),co.getRadius(),dc.getApower(),dc.getBpower()); 
		nouvo.getNeighbours(dc); 
		return nouvo; 
	}
	
	
   public GeneralizedCircle inverte(GeneralizedCircle gc){
	   double A=gc.getGca(); 
	   double D=gc.getGcd(); 
	   Complexe B=gc.getGcb(); 
	   Complexe C=gc.getGcc();
	   
	   double r2aa=this.radius*this.radius-this.center.squareNorm(); 
	   
	   // A'
	   double newA=A*this.center.squareNorm()+D; 
	   Complexe Ba=Complexe.mul(B,this.center);
	   Complexe Ca=Complexe.mul(C,this.center.conjugate()); 
	   Complexe bcaa=Complexe.sum(Ba,Ca);
	   newA=newA+bcaa.getReal();
	   
	   // B'
	   Complexe newB=Complexe.mulbyDouble(this.center.conjugate(),A*r2aa);
	   Complexe br=Complexe.mulbyDouble(B,r2aa); 
	   Complexe caa=Complexe.mul(C,this.center.conjugate()); 
	   caa=Complexe.mul(caa,this.center.conjugate()); 
	   caa=Complexe.mulbyDouble(caa,-1); 
	   Complexe ad=Complexe.mulbyDouble(this.center.conjugate(),-D); 
	   newB=Complexe.sum(newB,br); 
	   newB=Complexe.sum(newB,caa);
	   newB=Complexe.sum(newB, ad);
	   
	   // C'
	   Complexe newC=Complexe.mulbyDouble(this.center,A*r2aa);
	   Complexe cr=Complexe.mulbyDouble(C,r2aa); 
	   Complexe baa=Complexe.mul(B,this.center); 
	   baa=Complexe.mul(baa,this.center); 
	   baa=Complexe.mulbyDouble(baa,-1); 
	   Complexe ad2=Complexe.mulbyDouble(this.center,-D); 
	   newC=Complexe.sum(newC,cr); 
	   newC=Complexe.sum(newC,baa);
	   newC=Complexe.sum(newC, ad2);
	   
	   // D'
	   double newD=A*r2aa*r2aa+D*this.center.squareNorm();
	   Complexe barr=Complexe.mul(B,this.center);
	   Complexe carr=Complexe.mul(C, this.center.conjugate()); 
	   Complexe cba=Complexe.sum(barr,carr); 
	   cba=Complexe.mulbyDouble(cba, -r2aa); 
	   newD=newD+cba.getReal(); 
	   
	   return new GeneralizedCircle(newA,newB,newC,newD); 
   }

	/**
	 * @return the center
	 */
	public Complexe getCenter() {
		return center;
	}

	/**
	 * @param center the center to set
	 */
	public void setCenter(Complexe center) {
		this.center = center;
	}

	/**
	 * @return the ci
	 */
	public Circle getCi() {
		return ci;
	}

	/**
	 * @param ci the ci to set
	 */
	public void setCi(Circle ci) {
		this.ci = ci;
	}

	/**
	 * @return the radius
	 */
	public double getRadius() {
		return radius;
	}

	/**
	 * @param radius the radius to set
	 */
	public void setRadius(double radius) {
		this.radius = radius;
	}

}
